package org.xqh.utils.excel;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * easy poi
 */
public final class EasyPoiUtils {

	private EasyPoiUtils() {
	}

	private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
		try {
			response.setCharacterEncoding("UTF-8");
			response.setHeader("content-Type", "application/vnd.ms-excel");
			response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
			workbook.write(response.getOutputStream());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 导出多个sheet
	 * @param sheetModels
	 * @param fileName
	 * @param response
	 */
	public static void exportMultiSheet(List<ExportSheetModel> sheetModels, String fileName, HttpServletResponse response){
		Workbook workBook = wrapperWorkbook(sheetModels, fileName);
		if(Objects.nonNull(workBook)){
			downLoadExcel(fileName, response, workBook);
		}
	}

	/**
	 * 封装获取 workbook对象
	 * @param sheetModels
	 * @return
	 */
	public static Workbook wrapperWorkbook(List<ExportSheetModel> sheetModels, String fileName){
		ExcelType excelType = null;
		if(fileName.endsWith(".xlsx")){
			excelType = ExcelType.XSSF;
		}else if(fileName.endsWith(".xls")){
			excelType = ExcelType.HSSF;
		}
		if(Objects.isNull(excelType)){
			return null;
		}
		if(CollectionUtils.isEmpty(sheetModels)){
			return null;
		}
		List<Map<String, Object>> sheetsList = Lists.newArrayList();
		ExcelType finalExcelType = excelType;
		sheetModels.stream().forEach(s-> {
			ExportParams exportParams = new ExportParams(s.getTitle(), s.getSheetName(), finalExcelType);
			Map<String, Object> itemMap = Maps.newHashMap();
			itemMap.put("title", exportParams);
			itemMap.put("entity", s.getEntity());
			itemMap.put("data", s.getData());
			sheetsList.add(itemMap);
		});
		Workbook workBook = ExcelExportUtil.exportExcel(sheetsList, excelType);
		return workBook;
	}

	public static void exportToFile(ExportSheetModel sheetModel, String filePath){
		exportToFile(Lists.newArrayList(sheetModel), filePath);
	}


	public static void exportToFile(List<ExportSheetModel> sheetModels, String filePath){
		Workbook workBook = wrapperWorkbook(sheetModels, filePath);
		if(Objects.isNull(workBook)){
			return ;
		}
		FileOutputStream o = null;
		File file = null;
		try {
			file = new File(filePath);
			o = new FileOutputStream(file);
			workBook.write(o);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(Objects.nonNull(o)){
				try {
					o.flush();
					o.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 导出多sheet
	 * @param <T>
	 */
	@Data
	@Builder
	@AllArgsConstructor
	@NoArgsConstructor
	public static class ExportSheetModel<T>{
		private String title;
		private String sheetName;
		private Class<T> entity;
		private List<T> data;
	}

	private static <T> void defaultExport(List<T> dataList, Class<?> clz, String fileName, HttpServletResponse response, ExportParams exportParams) {
		Workbook workbook = ExcelExportUtil.exportExcel(exportParams, clz, dataList);
		if (workbook != null) {
			downLoadExcel(fileName, response, workbook);
		}
	}

	public static <T> void exportExcel(List<T> dataList, String title, String sheetName, Class<?> clz, String fileName, boolean isCreateHeader, HttpServletResponse response) {
		ExportParams exportParams = new ExportParams(title, sheetName);
		exportParams.setCreateHeadRows(isCreateHeader);
		defaultExport(dataList, clz, fileName, response, exportParams);
	}

	public static <T> void exportExcel(List<T> dataList, String title, String sheetName, Class<?> clz, String fileName, HttpServletResponse response) {
		defaultExport(dataList, clz, fileName, response, new ExportParams(title, sheetName));
	}

	private static void defaultExport(List<Map<String, Object>> dataList, String fileName, HttpServletResponse response) {
		Workbook workbook = ExcelExportUtil.exportExcel(dataList, ExcelType.HSSF);
		if (workbook != null) {
			downLoadExcel(fileName, response, workbook);
		}
	}

	public static void exportExcel(List<Map<String, Object>> dataList, String fileName, HttpServletResponse response) {
		defaultExport(dataList, fileName, response);
	}

	public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> clz) {
		if (StringUtils.isBlank(filePath)) {
			return null;
		}

		ImportParams params = new ImportParams();
		params.setTitleRows(titleRows);
//		params.setHeadRows(headerRows);

		try {
			return ExcelImportUtil.importExcel(new File(filePath), clz, params);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Boolean needVerify, Class<T> clz) {
		if (file == null) {
			return null;
		}

		ImportParams params = new ImportParams();
		params.setTitleRows(titleRows);
		params.setHeadRows(headerRows);
		params.setNeedVerify(needVerify);

		try {
			return ExcelImportUtil.importExcel(file.getInputStream(), clz, params);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 导入数据
	 * bo 你自己新建的实体类 实体类代码在下面
	 *
	 * @param file
	 * @param clz
	 * @return
	 */
	public static <T> List<T> importExcel(MultipartFile file, Class<T> clz) {
		if (file == null) {
			return null;
		}
		ImportParams params = new ImportParams();
		params.setTitleRows(1);
		params.setNeedVerify(true);
		try {
			return ExcelImportUtil.importExcel(file.getInputStream(), clz, params);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}
